#include "ATMOS_Packet.h"
#include "ATMOS_NetworkManager.h"

#include "BitStream.h"

using namespace ATMOS;

Packet::Packet( PacketID packetID, const std::string &rakNetGUID ) :
mRakNetGUID( rakNetGUID ),
mPacketID( packetID ),
mBitStream( 0 )
{
	mBitStream = new RakNet::BitStream();

	mBitStream->Write( NetworkManager::sAtmosCustomPacketID );
	mBitStream->Write( (unsigned char)packetID );
	writeString( rakNetGUID );
}

Packet::Packet( unsigned char *data, unsigned int size ) :
mPacketID( API_NULL ),
mBitStream( 0 )
{
	mBitStream = new RakNet::BitStream( data, size, false );

	unsigned char rakID = 0, atmosID = 0;
	mBitStream->Read( rakID );
	mBitStream->Read( atmosID );
	mRakNetGUID = readString();
	
	mPacketID = (PacketID)atmosID;
}

Packet::~Packet()
{
	if( mBitStream )
	{
		delete mBitStream;
	}
}

const std::string &Packet::getRakNetGUID() const
{
	return mRakNetGUID;
}

PacketID Packet::getAtmosPacketID() const
{
	return mPacketID;
}

void Packet::writeUChar( unsigned char c )
{
	mBitStream->Write( c );
}

void Packet::writeChar( char c )
{
	mBitStream->Write( c );
}

void Packet::writeString( const std::string &string )
{
	mBitStream->Write( (unsigned int)string.size() );
	for( unsigned int i = 0; i < string.size(); ++i ) mBitStream->Write( string[i] );
}

void Packet::writeUInt( unsigned int i )
{
	mBitStream->Write( i );
}

void Packet::writeInt( int i )
{
	mBitStream->Write( i );
}

void Packet::writeFloat( float f )
{
	mBitStream->Write( f );
}

void Packet::writeDouble( double d )
{
	mBitStream->Write( d );
}

unsigned char Packet::readUChar()
{
	unsigned char c = 0;
	mBitStream->Read( c );
	return c;
}

char Packet::readChar()
{
	char c = 0;
	mBitStream->Read( c );
	return c;
}

std::string Packet::readString()
{
	std::string out;
	unsigned int size = readUInt();
	for( unsigned int i = 0; i < size; ++i )
	{
		out.push_back( readChar() );
	}
	return out;
}

unsigned int Packet::readUInt()
{
	unsigned int i = 0;
	mBitStream->Read( i );
	return i;
}

int Packet::readInt()
{
	int i = 0;
	mBitStream->Read( i );
	return i;
}

float Packet::readFloat()
{
	float f = 0.0f;
	mBitStream->Read( f );
	return f;
}

double Packet::readDouble()
{
	float d = 0.0;
	mBitStream->Read( d );
	return d;
}

RakNet::BitStream *Packet::getBitStream()
{
	return mBitStream;
}

#define CASE_ID_AND_NAME( x ) case x : ret = #x ; break;

const char *Packet::idToString( PacketID id )
{
	const char *ret = 0;
	switch( id )
	{
		CASE_ID_AND_NAME( API_REGISTER_CLIENT );
		CASE_ID_AND_NAME( API_UNREGISTER_CLIENT );
		CASE_ID_AND_NAME( API_DEBUG_1 );
		CASE_ID_AND_NAME( API_DEBUG_2 );
		CASE_ID_AND_NAME( API_RESERVED_1 );
		CASE_ID_AND_NAME( API_RESERVED_2 );
		CASE_ID_AND_NAME( API_RESERVED_3 );
		CASE_ID_AND_NAME( API_RESERVED_4 );
		CASE_ID_AND_NAME( API_RESERVED_5 );
		CASE_ID_AND_NAME( API_RESERVED_6 );
		CASE_ID_AND_NAME( API_RESERVED_7 );
		CASE_ID_AND_NAME( API_RESERVED_8 );
		CASE_ID_AND_NAME( API_RESERVED_9 );
		CASE_ID_AND_NAME( API_RESERVED_10 );
		CASE_ID_AND_NAME( API_RESERVED_11 );
		CASE_ID_AND_NAME( API_RESERVED_12 );
		CASE_ID_AND_NAME( API_RESERVED_13 );
		CASE_ID_AND_NAME( API_RESERVED_14 );
		CASE_ID_AND_NAME( API_RESERVED_15 );
		CASE_ID_AND_NAME( API_RESERVED_16 );
		CASE_ID_AND_NAME( API_RESERVED_17 );
		CASE_ID_AND_NAME( API_RESERVED_18 );
		CASE_ID_AND_NAME( API_RESERVED_19 );
		CASE_ID_AND_NAME( API_RESERVED_20 );
		CASE_ID_AND_NAME( API_MASTER_SERVER );
	}
	return ret;
}

void Packet::setSeekPosition( uint position )
{
	mBitStream->SetReadOffset( position );
}
